from typing import List, Optional, Dict, Any
import logging
import asyncio
from app.models.movie import Movie
from app.services.maoyan_api_service import maoyanApiService, MaoyanApiService
from app.services.tmdb_api_service import TMDBApiService
from app.services.auth_service import AuthService
from sqlalchemy.orm import Session

logger = logging.getLogger(__name__)

class RecommendationService:
    """推荐服务：封装热映电影的获取与缓存逻辑"""
    
    def __init__(self, maoyan_service: MaoyanApiService, tmdb_service: TMDBApiService = None, auth_service: AuthService = None):
        self.maoyan_service = maoyan_service  # 依赖猫眼API服务
        self.tmdb_service = tmdb_service or TMDBApiService()  # 依赖TMDB API服务
        self.auth_service = auth_service or AuthService()  # 依赖认证服务
        self.cached_hot_movies: Optional[List[Movie]] = None  # 缓存热映电影
        self.cached_coming_soon_movies: Optional[List[Movie]] = None  # 缓存即将上映电影
        self.cached_personalized_movies: Dict[int, List[Movie]] = {}  # 缓存个性化推荐电影（按用户ID）

    async def get_hot_movies(self, limit: int = 20) -> List[Movie]:
        """获取正在热映电影（优先从缓存读取）"""
        # 缓存为空时，调用猫眼API获取并转换数据
        if not self.cached_hot_movies:
            raw_movies = self.maoyan_service.get_hot_movies(limit)  # 调用猫眼API
            # 转换为项目通用的Movie模型
            self.cached_hot_movies = [
                self.maoyan_service.convert_to_hot_movie(movie)
                for movie in raw_movies
            ]
        # 返回前limit条缓存数据
        return self.cached_hot_movies[:limit]
    
    async def get_coming_soon_movies(self, ci: int = 10, limit: int = 10) -> List[Movie]:
        """获取即将上映电影（优先从缓存读取）"""
        # 缓存为空时，调用猫眼API获取并转换数据
        if not self.cached_coming_soon_movies:
            raw_movies = self.maoyan_service.get_coming_soon_movies(ci, limit)  # 调用猫眼API
            # 转换为项目通用的Movie模型
            self.cached_coming_soon_movies = [
                self.maoyan_service.convert_to_coming_soon_movie({"detailMovie": movie})
                for movie in raw_movies
            ]
        # 返回前limit条缓存数据
        return self.cached_coming_soon_movies[:limit]
    
    async def get_movie_detail(self, movie_id: int, source: str = None) -> Movie:
        """根据电影ID和来源获取电影详情
        
        Args:
            movie_id: 电影ID
            source: 电影来源 ("maoyan" 或 "tmdb")，如果未指定则尝试两个来源
        """
        if source == "tmdb":
            # 明确指定TMDB来源
            try:
                tmdb_detail = self.tmdb_service.get_movie_details(movie_id)
                if tmdb_detail:
                    return self.tmdb_service.convert_to_movie(tmdb_detail)
            except Exception as e:
                logger.error(f"Failed to get movie detail from TMDB for ID {movie_id}: {e}")
                raise Exception(f"无法从TMDB获取电影详情，电影ID: {movie_id}")
        
        elif source == "maoyan":
            # 明确指定猫眼来源
            try:
                raw_detail = self.maoyan_service.get_movie_detail(movie_id)
                return self.maoyan_service.convert_to_hot_movie(raw_detail)
            except Exception as e:
                logger.error(f"Failed to get movie detail from Maoyan for ID {movie_id}: {e}")
                raise Exception(f"无法从猫眼获取电影详情，电影ID: {movie_id}")
        
        else:
            # 未指定来源，按优先级尝试（猫眼优先，因为大部分电影来自猫眼）
            try:
                raw_detail = self.maoyan_service.get_movie_detail(movie_id)
                return self.maoyan_service.convert_to_hot_movie(raw_detail)
            except Exception as e:
                logger.warning(f"Failed to get movie detail from Maoyan for ID {movie_id}: {e}")
            
            try:
                tmdb_detail = self.tmdb_service.get_movie_details(movie_id)
                if tmdb_detail:
                    return self.tmdb_service.convert_to_movie(tmdb_detail)
            except Exception as e:
                logger.error(f"Failed to get movie detail from both Maoyan and TMDB for ID {movie_id}: {e}")
                raise Exception(f"无法获取电影详情，电影ID: {movie_id}")
    
    async def get_personalized_recommendations(self, user_id: int, db: Session, limit: int = 12) -> List[Movie]:
        """获取个性化推荐电影
        
        Args:
            user_id: 用户ID
            db: 数据库会话
            limit: 返回电影数量限制
        
        Returns:
            List[Movie]: 个性化推荐电影列表
        """
        try:
            # 检查缓存
            if user_id in self.cached_personalized_movies:
                cached_movies = self.cached_personalized_movies[user_id]
                if cached_movies:  # 只要有缓存就使用，不管数量
                    logger.info(f"Using cached personalized recommendations for user {user_id}, cached count: {len(cached_movies)}")
                    return cached_movies[:limit]
            
            # 使用超时控制获取推荐
            return await asyncio.wait_for(
                self._get_recommendations_internal(user_id, db, limit),
                timeout=20.0  # 20秒超时
            )
            
        except asyncio.TimeoutError:
            logger.error(f"Timeout getting personalized recommendations for user {user_id}")
            return []
        except Exception as e:
            logger.error(f"Error getting personalized recommendations for user {user_id}: {e}")
            return []
    
    async def _get_recommendations_internal(self, user_id: int, db: Session, limit: int) -> List[Movie]:
        """内部获取推荐的方法，用于超时控制"""
        # 获取用户画像数据
        user_profile_result = self.auth_service.get_user_profile_data(db, user_id)
        if not user_profile_result or not user_profile_result.get('success'):
            logger.warning(f"No user profile found for user {user_id}")
            return []
        
        user_profile = user_profile_result.get('data', {})
        recommended_movies = []
        
        # 1. 基于喜好类型推荐
        favorite_genres = user_profile.get('favorite_genres', [])
        if favorite_genres:
            genre_movies = await self._get_movies_by_genres(favorite_genres, limit_per_genre=2)
            recommended_movies.extend(genre_movies)
        
        # 2. 基于喜欢的演员推荐
        favorite_actors = user_profile.get('favorite_actors', [])
        if favorite_actors:
            actor_movies = await self._get_movies_by_actors(favorite_actors, limit_per_person=2)
            recommended_movies.extend(actor_movies)
        
        # 3. 基于喜欢的导演推荐
        favorite_directors = user_profile.get('favorite_directors', [])
        if favorite_directors:
            director_movies = await self._get_movies_by_directors(favorite_directors, limit_per_person=2)
            recommended_movies.extend(director_movies)
        
        # 去重并按评分排序
        unique_movies = self._deduplicate_and_sort_movies(recommended_movies)
        
        # 缓存结果
        self.cached_personalized_movies[user_id] = unique_movies
        logger.info(f"Cached personalized recommendations for user {user_id}, count: {len(unique_movies)}")
        
        return unique_movies[:limit]
    
    async def _get_movies_by_genres(self, genres: List[str], limit_per_genre: int = 2) -> List[Movie]:
        """根据类型获取电影"""
        movies = []
        for genre_name in genres:
            try:
                # 获取类型ID
                genre_id = self.tmdb_service.get_genre_id_by_name(genre_name)
                if genre_id:
                    # 获取该类型的电影
                    tmdb_movies = self.tmdb_service.get_movies_by_genre(genre_id, limit=limit_per_genre)
                    # 转换为Movie模型
                    for tmdb_movie in tmdb_movies:
                        movie = self.tmdb_service.convert_to_movie(tmdb_movie)
                        movies.append(movie)
            except Exception as e:
                logger.error(f"Error getting movies for genre {genre_name}: {e}")
                continue
        return movies
    
    async def _get_movies_by_actors(self, actors: List[str], limit_per_person: int = 2) -> List[Movie]:
        """根据演员获取电影"""
        movies = []
        for actor_name in actors:
            try:
                # 获取演员的电影作品
                tmdb_movies = self.tmdb_service.get_movies_by_person(
                    actor_name, limit=limit_per_person, role="actor"
                )
                # 转换为Movie模型
                for tmdb_movie in tmdb_movies:
                    movie = self.tmdb_service.convert_to_movie(tmdb_movie)
                    movies.append(movie)
            except Exception as e:
                logger.error(f"Error getting movies for actor {actor_name}: {e}")
                continue
        return movies
    
    async def _get_movies_by_directors(self, directors: List[str], limit_per_person: int = 2) -> List[Movie]:
        """根据导演获取电影"""
        movies = []
        for director_name in directors:
            try:
                # 获取导演的电影作品
                tmdb_movies = self.tmdb_service.get_movies_by_person(
                    director_name, limit=limit_per_person, role="director"
                )
                # 转换为Movie模型
                for tmdb_movie in tmdb_movies:
                    movie = self.tmdb_service.convert_to_movie(tmdb_movie)
                    movies.append(movie)
            except Exception as e:
                logger.error(f"Error getting movies for director {director_name}: {e}")
                continue
        return movies
    
    def _deduplicate_and_sort_movies(self, movies: List[Movie]) -> List[Movie]:
        """去重并按评分排序"""
        # 使用字典去重（以电影ID为键）
        unique_movies_dict = {}
        for movie in movies:
            if movie.id not in unique_movies_dict:
                unique_movies_dict[movie.id] = movie
            # 如果已存在，保留评分更高的
            elif movie.rating > unique_movies_dict[movie.id].rating:
                unique_movies_dict[movie.id] = movie
        
        # 转换为列表并按评分排序
        unique_movies = list(unique_movies_dict.values())
        unique_movies.sort(key=lambda x: x.rating, reverse=True)
        
        return unique_movies
    
    def clear_personalized_cache(self, user_id: int = None):
        """清除个性化推荐缓存"""
        if user_id:
            self.cached_personalized_movies.pop(user_id, None)
        else:
            self.cached_personalized_movies.clear()

# 使用单例模式确保缓存持久性
_recommendation_service_instance = None

def get_recommendation_service_instance():
    """获取RecommendationService单例实例"""
    global _recommendation_service_instance
    if _recommendation_service_instance is None:
        from app.services.tmdb_api_service import TMDBApiService
        from app.services.auth_service import AuthService
        tmdb_service = TMDBApiService()
        auth_service = AuthService()
        _recommendation_service_instance = RecommendationService(maoyanApiService, tmdb_service, auth_service)
    return _recommendation_service_instance

# 保持向后兼容
recommendationService = get_recommendation_service_instance()